package xj.model.uml;

import static xj.model.uml.UMLModelConstants.*;

import java.util.*;

public class UMLClass 
  extends Classifier {

  public UMLClass() {
    this(null);
  }

  public UMLClass(String name) {
    super(name);
    destructable = true;

    setVisibility(Visibility.Public);

    superTypes = new ArrayList<SuperType>();
    attributes = new ArrayList<Attribute>();
    operations = new ArrayList<Operation>();
  }

  @Override
  public Object clone() throws CloneNotSupportedException {
    //System.out.println("UMLClass.clone()");
    
    UMLClass cls = (UMLClass) super.clone();

    cls.setInterface(interface_);
    cls.setAbstract(abstract_);
    cls.setActive(active);
    cls.setEnum(enum_);
    cls.setException(exception);
    cls.setMixin(mixin);

    cls.attributes = new ArrayList<Attribute>();
    Iterator<Attribute> iter1 = attributes.iterator();
    while (iter1.hasNext()) {
      Attribute f = iter1.next();
      cls.addAttribute((Attribute) f.clone());
    }

    cls.operations = new ArrayList<Operation>();
    Iterator<Operation> iter2 = operations.iterator();
    while (iter2.hasNext()) {
      Operation m = iter2.next();
      cls.addOperation((Operation) m.clone());
    }

    cls.superTypes = new ArrayList<SuperType>();
    Iterator<SuperType> iter3 = superTypes.iterator();
    while (iter3.hasNext()) {
      SuperType t = iter3.next();
      cls.addSuperType((SuperType) t.clone());
    }

    return cls;
  }

  public boolean isInterface() {
    return interface_;
  }

  public void setInterface(boolean b) {
    interface_ = b;
    setAttribute(ATTR_IS_INTERFACE, b);
    setStereotypes();
  }

  public boolean isAbstract() {
    return abstract_;
  }

  public void setAbstract(boolean b) {
    abstract_ = b;
    setAttribute(ATTR_IS_ABSTRACT, b);
    setStereotypes();
  }

  public boolean isActive() {
    return active;
  }

  public void setActive(boolean b) {
    active = b;
    setAttribute(ATTR_IS_ACTIVE, b);
    setStereotypes();
  }

  public boolean isEnum() {
    return enum_;
  }

  public void setEnum(boolean b) {
    enum_ = b;
    setAttribute(ATTR_IS_ENUM, b);
    setStereotypes();
  }

  public boolean isException() {
    return exception;
  }

  public void setException(boolean b) {
    exception = b;
    setAttribute(ATTR_IS_EXCEPTION, b);
    setStereotypes();
  }

  public boolean isMixin() {
    return mixin;
  }

  public void setMixin(boolean b) {
    mixin = b;
    setAttribute(ATTR_IS_MIXIN, b);
    setStereotypes();
  }

  public List<SuperType> getSuperTypes() {
    return superTypes;
  }

  public void addSuperType(SuperType c) {
    if (c != null) {
      superTypes.add(c);
      addOwnedElement(c, ROLE_SUPER_TYPE);
    }
  }

  public void removeSuperType(SuperType c) {
    if (c != null) {
      superTypes.remove(c);
      removeOwnedElement(c);
    }
  }

  public void removeAllSuperTypes() {
    Iterator<SuperType> iter = superTypes.iterator(); 
    while (iter.hasNext()) {
      SuperType c = iter.next(); 
      removeOwnedElement(c);
      iter.remove();
    }
  }

  public List<Attribute> getAttributes() {
    return attributes;
  }

  public void addAttribute(Attribute f) {
    if (f != null) {
      attributes.add(f);
      addOwnedElement(f, ROLE_ATTRIBUTE);
    }
  }

  public void removeAttribute(Attribute f) {
    if (f != null) {
      attributes.remove(f);
      removeOwnedElement(f);
    }
  }

  public void removeAllAttributes() {
    Iterator<Attribute> iter = attributes.iterator();
    while (iter.hasNext()) {
      Attribute f = iter.next();
      removeOwnedElement(f);
      iter.remove();
    }
  }

  public Attribute findAttribute(String name) {
    if (name != null) {
      Iterator<Attribute> iter = attributes.iterator();
      while (iter.hasNext()) {
	Attribute f = iter.next();
	if (name.equals(f.getName())) {
	  return f;
	}
      }
    }
    return null;
  }

  public List<Operation> getOperations() {
    return operations;
  }

  public void addOperation(Operation m) {
    if (m != null) {
      operations.add(m);
      addOwnedElement(m, ROLE_OPERATION);
    }
  }

  public void removeOperation(Operation m) {
    if (m != null) {
      operations.remove(m);
      removeOwnedElement(m);
    }
  }

  public Operation findOperation(String name) {
    if (name != null) {
      Iterator<Operation> iter = operations.iterator();
      while (iter.hasNext()) {
	Operation m = iter.next();
	if (name.equals(m.getName())) {
	  return m;
	}
      }
    }
    return null;
  }

  public void removeAllOperations() {
    Iterator<Operation> iter = operations.iterator();
    while (iter.hasNext()) {
      Operation m = iter.next();
      removeOwnedElement(m);
      iter.remove();
    }
  }

  protected void setStereotypes() { 
    removeStereotypes(STEREOTYPES); 
    if (interface_) { 
      addStereotype("interface");
    } else if (abstract_) { 
      addStereotype("abstract");
    } else if (enum_) { 
      addStereotype("enumeration");
    } else if (exception) { 
      addStereotype("exception");
    } else if (mixin) { 
      addStereotype("mixin");
    }
  }

  protected static final Set<String> STEREOTYPES = new HashSet<String>();

  static { 
    STEREOTYPES.add("interface"); 
    STEREOTYPES.add("abstract"); 
    STEREOTYPES.add("enumeration"); 
    STEREOTYPES.add("exception"); 
    STEREOTYPES.add("mixin"); 
  }

  @Override
  public String toString() {
    return "UMLClass name=" + name;
  }

  protected List<SuperType> superTypes;

  protected List<Attribute> attributes;

  protected List<Operation> operations;

  protected boolean interface_ = false;

  protected boolean abstract_ = false;

  protected boolean active = false;

  protected boolean enum_ = false;

  protected boolean exception = false;

  protected boolean mixin = false; 

}
